﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;

namespace Swaf.Remoting
{
	public class ServerSink : IServerChannelSink
	{
		protected IServerChannelSink m_next = null;
		protected SoapServerFormatterSink m_sink;

		public ServerSink(IServerChannelSink next, IChannelReceiver chan)
		{
			m_next = next;
			m_sink = new SoapServerFormatterSink(SoapServerFormatterSink.Protocol.Http, next, chan);
		}

		#region IServerChannelSink Members

		public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, object state, IMessage msg, ITransportHeaders headers, System.IO.Stream stream)
		{
			throw new NotImplementedException();
		}

		public System.IO.Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, object state, IMessage msg, ITransportHeaders headers)
		{
			throw new NotImplementedException();
		}

		public IServerChannelSink NextChannelSink
		{
			get { return m_next = m_sink.NextChannelSink ; }
		}

		public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, 
			ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, 
			out ITransportHeaders responseHeaders, out Stream responseStream)
		{

			//ServerProcessing tp = m_sink.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg,
			//	out responseHeaders, out responseStream);
			//return tp;

			responseMsg = null;
			responseHeaders = null;
			responseStream = null;

			RemotingSurrogateSelector remSs = new RemotingSurrogateSelector();
			SoapFormatter formatter = new SoapFormatter();
			formatter.Binder = new FlexiSerializationBinder();
			formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
			formatter.FilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
			formatter.TypeFormat = System.Runtime.Serialization.Formatters.FormatterTypeStyle.TypesWhenNeeded;
			formatter.SurrogateSelector = null;
			formatter.Context = new StreamingContext(StreamingContextStates.Other);
			//TextReader rdr = new StreamReader(requestStream);
			//string val = rdr.ReadToEnd();
			string soapActionToVerify;
			MethodCall c = new MethodCall(getChannelHeaders(requestHeaders, out soapActionToVerify));
			formatter.Deserialize(requestStream, new HeaderHandler(c.HeaderHandler));

			sinkStack.Push(this, null);
			ServerProcessing p = NextChannelSink.ProcessMessage(sinkStack, c, requestHeaders, null, out responseMsg, out responseHeaders, out responseStream);
			sinkStack.Pop(this);

			if (p == ServerProcessing.Complete)
			{
				if (responseMsg != null && responseStream == null)
				{
					BaseTransportHeaders headers2 = new BaseTransportHeaders();
					if (responseHeaders != null)
					{
						foreach (DictionaryEntry entry in responseHeaders)
						{
							headers2[entry.Key] = entry.Value;
						}
					}
					responseHeaders = headers2;
					headers2.ContentType = "text/xml; charset=\"utf-8\"";
					
					responseStream = sinkStack.GetResponseStream(responseMsg, responseHeaders);
					if (responseStream == null)
						responseStream = new MemoryStream();
					remSs = new RemotingSurrogateSelector();
					formatter.SurrogateSelector = remSs;
					remSs.UseSoapFormat();
					((RemotingSurrogateSelector)formatter.SurrogateSelector).SetRootObject(responseMsg);
					formatter.Serialize(responseStream, responseMsg, GetMessagePropertiesAsSoapHeader(responseMsg));
				}
			}

			return p;
		}

		#endregion

		#region IChannelSinkBase Members

		public System.Collections.IDictionary Properties
		{
			get { return null; }
		}

		#endregion

		private Header[] getChannelHeaders(ITransportHeaders requestHeaders, out string soapActionToVerify)
		{
			string str3;
			string str4;
			soapActionToVerify = null;
			string uRI = (string)requestHeaders["__RequestUri"];
			string uri = (string)requestHeaders["SOAPAction"];
			if (uri == null)
			{
				throw new BaseException("Remoting_SoapActionMissing");
			}
			//uri = HttpEncodingHelper.DecodeUri(uri);
			soapActionToVerify = uri;
			if (!SoapServices.GetTypeAndMethodNameFromSoapAction(uri, out str3, out str4))
			{
				Type serverTypeForUri = RemotingServices.GetServerTypeForUri(uRI);
				if (serverTypeForUri == null)
				{
					throw new BaseException("Remoting_TypeNotFoundFromUri");
				}
				str3 = "clr:" + serverTypeForUri.FullName + ", " + serverTypeForUri.Assembly.GetName().Name;
			}
			else
			{
				str3 = "clr:" + str3;
			}
			int num = 2;
			Header[] headerArray = new Header[num];
			headerArray[0] = new Header("__Uri", uRI);
			headerArray[1] = new Header("__TypeName", str3);
			return headerArray;
		}


		internal static Header[] GetMessagePropertiesAsSoapHeader(IMessage reqMsg)
		{
			IDictionary properties = reqMsg.Properties;
			if (properties == null)
			{
				return null;
			}
			int count = properties.Count;
			if (count == 0)
			{
				return null;
			}
			IDictionaryEnumerator enumerator = properties.GetEnumerator();
			bool[] flagArray = new bool[count];
			int num2 = 0;
			int index = 0;
			IMethodMessage msg = (IMethodMessage)reqMsg;
			while (enumerator.MoveNext())
			{
				string key = (string)enumerator.Key;
				if (((key.Length >= 2) && (string.CompareOrdinal(key, 0, "__", 0, 2) == 0)) && (((((key.Equals("__Args") || key.Equals("__OutArgs")) || (key.Equals("__Return") || key.Equals("__Uri"))) || (key.Equals("__MethodName") || ((key.Equals("__MethodSignature") && !RemotingServices.IsMethodOverloaded(msg)) && !msg.HasVarArgs))) || (key.Equals("__TypeName") || key.Equals("__Fault"))) || (key.Equals("__CallContext") && ((enumerator.Value != null) ? !((LogicalCallContext)enumerator.Value).HasInfo : true))))
				{
					index++;
				}
				else
				{
					flagArray[index] = true;
					index++;
					num2++;
				}
			}
			if (num2 == 0)
			{
				return null;
			}
			Header[] sourceArray = new Header[num2];
			enumerator.Reset();
			int num4 = 0;
			index = 0;
			while (enumerator.MoveNext())
			{
				object obj2 = enumerator.Key;
				if (!flagArray[num4])
				{
					num4++;
				}
				else
				{
					Header header = enumerator.Value as Header;
					if (header == null)
					{
						header = new Header((string)obj2, enumerator.Value, false, "http://schemas.microsoft.com/clr/soap/messageProperties");
					}
					if (index == sourceArray.Length)
					{
						Header[] destinationArray = new Header[index + 1];
						Array.Copy(sourceArray, destinationArray, index);
						sourceArray = destinationArray;
					}
					sourceArray[index] = header;
					index++;
					num4++;
				}
			}
			return sourceArray;
		}

 

 

 

	}

	public class ServerSinkProvider : IServerFormatterSinkProvider
	{
		protected IServerChannelSinkProvider m_next;

		public ServerSinkProvider()
		{
		}

		public ServerSinkProvider(IDictionary properties, ICollection providerData)
		{
		}

		#region IServerChannelSinkProvider Members

		public IServerChannelSink CreateSink(IChannelReceiver channel)
		{
			IServerChannelSink chain = Next.CreateSink(channel);
			IServerChannelSink sinkFormatter = new ServerSink(chain, channel);
			return sinkFormatter;
		}

		public void GetChannelData(IChannelDataStore channelData)
		{
			if (Next != null)
				Next.GetChannelData(channelData);
		}

		public IServerChannelSinkProvider Next { get{return m_next;}set{m_next = value;}}
		#endregion
	}


[Serializable]
internal class BaseTransportHeaders : ITransportHeaders
{
    // Fields
    private object _connectionId;
    private string _contentType;
    private object _ipAddress;
    private ITransportHeaders _otherHeaders = null;
    private string _requestUri;
    internal const int WellknownHeaderCount = 4;

    // Methods
    public IEnumerator GetEnumerator()
    {
        return new BaseTransportHeadersEnumerator(this);
    }

    internal IEnumerator GetOtherHeadersEnumerator()
    {
        if (this._otherHeaders == null)
        {
            return null;
        }
        return this._otherHeaders.GetEnumerator();
    }

    internal object GetValueFromHeaderIndex(int index)
    {
        switch (index)
        {
            case 0:
                return this._connectionId;

            case 1:
                return this._ipAddress;

            case 2:
                return this._requestUri;

            case 3:
                return this._contentType;
        }
        return null;
    }

    internal string MapHeaderIndexToName(int index)
    {
        switch (index)
        {
            case 0:
                return "__ConnectionId";

            case 1:
                return "__IPAddress";

            case 2:
                return "__RequestUri";

            case 3:
                return "Content-Type";
        }
        return null;
    }

    internal int MapHeaderNameToIndex(string headerName)
    {
        if (string.Compare(headerName, "__ConnectionId", StringComparison.OrdinalIgnoreCase) == 0)
        {
            return 0;
        }
        if (string.Compare(headerName, "__IPAddress", StringComparison.OrdinalIgnoreCase) == 0)
        {
            return 1;
        }
        if (string.Compare(headerName, "__RequestUri", StringComparison.OrdinalIgnoreCase) == 0)
        {
            return 2;
        }
        if (string.Compare(headerName, "Content-Type", StringComparison.OrdinalIgnoreCase) == 0)
        {
            return 3;
        }
        return -1;
    }

    internal void SetValueFromHeaderIndex(int index, object value)
    {
        switch (index)
        {
            case 0:
                this._connectionId = value;
                return;

            case 1:
                this._ipAddress = value;
                return;

            case 2:
                this._requestUri = (string) value;
                return;

            case 3:
                this._contentType = (string) value;
                return;
        }
    }

    // Properties
    public object ConnectionId
    {
        set
        {
            this._connectionId = value;
        }
    }

    public string ContentType
    {
        get
        {
            return this._contentType;
        }
        set
        {
            this._contentType = value;
        }
    }

    public IPAddress IPAddress
    {
        set
        {
            this._ipAddress = value;
        }
    }

    public object this[object key]
    {
        get
        {
            string headerName = key as string;
            if (headerName != null)
            {
                int index = this.MapHeaderNameToIndex(headerName);
                if (index != -1)
                {
                    return this.GetValueFromHeaderIndex(index);
                }
            }
            if (this._otherHeaders != null)
            {
                return this._otherHeaders[key];
            }
            return null;
        }
        set
        {
            bool flag = false;
            string headerName = key as string;
            if (headerName != null)
            {
                int index = this.MapHeaderNameToIndex(headerName);
                if (index != -1)
                {
                    this.SetValueFromHeaderIndex(index, value);
                    flag = true;
                }
            }
            if (!flag)
            {
                if (this._otherHeaders == null)
                {
                    this._otherHeaders = new TransportHeaders();
                }
                this._otherHeaders[key] = value;
            }
        }
    }

    public string RequestUri
    {
        get
        {
            return this._requestUri;
        }
        set
        {
            this._requestUri = value;
        }
    }
}
internal class BaseTransportHeadersEnumerator : IEnumerator
{
    // Fields
    private bool _bStarted;
    private int _currentIndex;
    private BaseTransportHeaders _headers;
    private IEnumerator _otherHeadersEnumerator;

    // Methods
    public BaseTransportHeadersEnumerator(BaseTransportHeaders headers)
    {
        this._headers = headers;
        this.Reset();
    }

    public bool MoveNext()
    {
        if (this._currentIndex != -1)
        {
            if (this._bStarted)
            {
                this._currentIndex++;
            }
            else
            {
                this._bStarted = true;
            }
            while (this._currentIndex != -1)
            {
                if (this._currentIndex >= 4)
                {
                    this._otherHeadersEnumerator = this._headers.GetOtherHeadersEnumerator();
                    this._currentIndex = -1;
                }
                else
                {
                    if (this._headers.GetValueFromHeaderIndex(this._currentIndex) != null)
                    {
                        return true;
                    }
                    this._currentIndex++;
                }
            }
        }
        if (this._otherHeadersEnumerator == null)
        {
            return false;
        }
        if (!this._otherHeadersEnumerator.MoveNext())
        {
            this._otherHeadersEnumerator = null;
            return false;
        }
        return true;
    }

    public void Reset()
    {
        this._bStarted = false;
        this._currentIndex = 0;
        this._otherHeadersEnumerator = null;
    }

    // Properties
    public object Current
    {
        get
        {
            if (this._bStarted)
            {
                if (this._currentIndex != -1)
                {
                    return new DictionaryEntry(this._headers.MapHeaderIndexToName(this._currentIndex), this._headers.GetValueFromHeaderIndex(this._currentIndex));
                }
                if (this._otherHeadersEnumerator != null)
                {
                    return this._otherHeadersEnumerator.Current;
                }
            }
            return null;
        }
    }
}
}
